#include "NTL/ZZ.h"
#include "NTL/vector.h"
//#include "boost/serialization/vector.hpp"
//#include "botan/bigint.h"
#include "example.hpp"
//#include "struct_pack.hpp"

#include <iostream>
#include <string>
#include <vector>

namespace boost {
namespace serialization {

// NTL::ZZ
template <class Archive>
inline void
save(Archive &ar, const NTL::ZZ &z, const unsigned int /* file_version */) {
    std::vector<unsigned char> buf(NTL::NumBytes(z));
    NTL::BytesFromZZ(buf.data(), z, static_cast<long>(buf.size()));
    ar &buf;
}

template <class Archive>
inline void
load(Archive &ar, NTL::ZZ &z, const unsigned int /* file_version */) {
    std::vector<unsigned char> buf;
    ar &buf;
    NTL::ZZFromBytes(z, buf.data(), static_cast<long>(buf.size()));
}

// NTL::ZZ ZZFromBotanBigInt(const Botan::BigInt &bigint) {
//    auto n = bigint.bytes();
//    auto *bytes = new unsigned char[n];
//    bigint.binary_encode(bytes, n);
//    unsigned char swapper{};
//    for (int i = 0; i < (n / 2); ++i) {
//        swapper = bytes[i];
//        bytes[i] = bytes[n - 1 - i];
//        bytes[n - 1 - i] = swapper;
//    }
//    NTL::ZZ zz;
//    ZZFromBytes(zz, bytes, n);
//    delete[] bytes;
//    return zz;
//}
//
// Botan::BigInt BotanBigIntFromZZ(const NTL::ZZ &zz) {
//    auto n = NTL::NumBytes(zz);
//    auto *bytes = new unsigned char[n];
//    BytesFromZZ(bytes, zz, n);
//    unsigned char swapper{};
//    for (int i = 0; i < (n / 2); ++i) {
//        swapper = bytes[i];
//        bytes[i] = bytes[n - 1 - i];
//        bytes[n - 1 - i] = swapper;
//    }
//    Botan::BigInt bigint;
//    bigint.binary_decode(bytes, n);
//    delete[] bytes;
//    return bigint;
//}
//
// template <class Archive>
// inline void save(Archive &ar,
//                 const Botan::BigInt &_b,
//                 const unsigned int /* file_version */) {
//    NTL::ZZ zz = ZZFromBotanBigInt(_b);
//    ar &zz;
//}
//
// template <class Archive>
// inline void load(Archive &ar,
//                 Botan::BigInt &bigint,
//                 const unsigned int /* file_version */) {
//    NTL::ZZ zz;
//    ar &zz;
//    bigint = BotanBigIntFromZZ(zz);
//}
} // namespace serialization
} // namespace boost
BOOST_SERIALIZATION_SPLIT_FREE(NTL::ZZ)
// BOOST_SERIALIZATION_SPLIT_FREE(Botan::BigInt)

struct Complex {
    // NTL::Vec<Botan::BigInt> sk; // sk = (a, b)
    // Botan::BigInt sk;
    NTL::ZZ sk;
    // int sk;
    std::vector<uint8_t> id;

    friend class boost::serialization::access;
    template <typename Archive>
    void serialize(Archive &ar, [[maybe_unused]] const unsigned int version) {
        ar &sk;
        ar &id;
    }
};
// STRUCT_PACK_REFL(Complex, sk, id);

int main() {
    // NTL::Vec<Botan::BigInt> sk;
    // sk.SetLength(2);
    // uint64_t sk0 = 1000;
    // uint64_t sk1 = 2000;
    // sk[0] = Botan::BigInt(sk0);
    // sk[1] = Botan::BigInt(sk1);
    // Botan::BigInt sk = 1000;
    NTL::ZZ sk(1000);
    // int sk = 1000;
    Complex complex1{.sk = sk, .id = {1, 2, 3}};

    // auto buffer = struct_pack::serialize<std::string>(complex1);
    auto buffer = boost_pack::serialize(complex1);
    std::cout << "buffer length: " << buffer.length() << '\n';

    // auto complex2 = struct_pack::deserialize<Complex>(buffer);
    // std::cout << "id[2]: " << int(complex2.value().id[2]) << '\n';
    auto complex2 = boost_pack::deserialize<Complex>(buffer);
    std::cout << "id[2]: " << int(complex2.id[2]) << '\n';
}
